﻿#region File Description
//-----------------------------------------------------------------------------
// TaskSet
//
// Copyright © 2013 Wave Coorporation. All rights reserved.
// Use is subject to license terms.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using System.Diagnostics;
using WaveEngine.Framework;
#endregion

namespace WaveEngine.Extensions.ITasks
{
    internal abstract class WaitCountTaskSetBase<T> : TaskBase
    {
        /// <summary>
        /// The child tasks
        /// </summary>
        protected T[] childTasks;

        /// <summary>
        /// Gets the completed.
        /// </summary>
        /// <value>
        /// The completed.
        /// </value>
        protected int completed { get; private set; }

        /// <summary>
        /// Gets the cancelled.
        /// </summary>
        /// <value>
        /// The cancelled.
        /// </value>
        protected int cancelled { get; private set; }

        /// <summary>
        /// Gets the count limit.
        /// </summary>
        /// <value>
        /// The count limit.
        /// </value>
        protected int CountLimit { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="WaitCountTaskSetBase{T}" /> class.
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="countLimit">The count limit.</param>
        /// <param name="childTasks">The child tasks.</param>
        public WaitCountTaskSetBase(ITask parent, string name, int countLimit, params T[] childTasks)
            : base(parent, name)
        {
            this.completed = 0;
            this.childTasks = childTasks;
            this.CountLimit = countLimit;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WaitCountTaskSetBase{T}" /> class.
        /// </summary>
        /// <param name="scene">The scene.</param>
        /// <param name="countLimit">The count limit.</param>
        /// <param name="childTasks">The child tasks.</param>
        public WaitCountTaskSetBase(Scene scene, string name, int countLimit, params T[] childTasks)
            : base(scene, name)
        {
            this.completed = 0;
            this.childTasks = childTasks;
            this.CountLimit = countLimit;
        }

        /// <summary>
        /// Task_s the cancelled.
        /// </summary>
        [DebuggerStepThrough]
        protected void task_Cancelled()
        {
            if (TaskState == WaveEngine.Framework.Services.TaskState.Running)
            {
                cancelled++;
                this.checkEnd();
            }
        }

        /// <summary>
        /// Task_s the completed.
        /// </summary>
        [DebuggerStepThrough]
        protected void task_Completed()
        {
            if (TaskState == WaveEngine.Framework.Services.TaskState.Running)
            {
                completed++;
                this.checkEnd();
            }
        }

        /// <summary>
        /// Checks the end.
        /// </summary>
        [DebuggerStepThrough]
        protected void checkEnd()
        {
            if (completed == this.CountLimit)
                this.performCompleted();
            /*
        else if (completed + cancelled == childTasks.Length)
            this.performCancel();*/
        }


        /// <summary>
        /// Ons the run.
        /// </summary>
        [DebuggerStepThrough]
        protected override void performRun()
        {
            // If no tasks, it will end suddenly
            this.checkEnd();
        }
    }

    //--------------------------------------------------------------------------
    internal class WaitCountTaskSet : WaitCountTaskSetBase<ITask>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="WaitCountTaskSet" /> class.
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="countLimit">The count limit.</param>
        /// <param name="childTasks">The child tasks.</param>
        public WaitCountTaskSet(ITask parent, string name, int countLimit, params ITask[] childTasks)
            : base(parent, name, countLimit, childTasks)
        {

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WaitCountTaskSet" /> class.
        /// </summary>
        /// <param name="scene">The scene.</param>
        /// <param name="countLimit">The count limit.</param>
        /// <param name="childTasks">The child tasks.</param>
        public WaitCountTaskSet(Scene scene, string name, int countLimit, params ITask[] childTasks)
            : base(scene, name, countLimit, childTasks)
        {

        }

        /// <summary>
        /// Notifies the skip.
        /// </summary>
        /// <returns></returns>
        [DebuggerStepThrough]
        protected override bool performSkip()
        {
            if (this.IsSkippable)
            {
                foreach (var t in this.childTasks)
                {
                    if (t.TaskState == WaveEngine.Framework.Services.TaskState.Running)
                        t.Cancel();
                }
                return base.performSkip();
            }
            else
            {
                bool skip = true;
                foreach (var t in this.childTasks)
                {
                    if (t.TaskState == WaveEngine.Framework.Services.TaskState.Running)
                        skip = skip & t.TrySkip();
                }
                return skip;
            }
        }

        /// <summary>
        /// Notifies the cancelled.
        /// </summary>
        [DebuggerStepThrough]
        protected override void performCancel()
        {
            foreach (ITask t in this.childTasks)
            {
                if (t.TaskState == WaveEngine.Framework.Services.TaskState.Running || t.TaskState == WaveEngine.Framework.Services.TaskState.Waiting)
                    t.Cancel();
            }
            base.performCancel();
        }

        /// <summary>
        /// Ons the run.
        /// </summary>
        [DebuggerStepThrough]
        protected override void performRun()
        {
            base.performRun();

            foreach (ITask task in childTasks)
            {
                task.Completed += task_Completed;
                task.Cancelled += task_Cancelled;

                //THIS WORKAROUND IS MADE FOR THE AndRundPArallely that shouldnt call twice to the run method
                //POSIBLE BUG FOR INMEDIATE PARALLEL ACTIONS
                {
                    if (task.TaskState == WaveEngine.Framework.Services.TaskState.Finished)
                    {
                        task_Completed();
                    }
                    else if (task.TaskState == WaveEngine.Framework.Services.TaskState.Aborted)
                        task_Cancelled();

                    if (task.TaskState != WaveEngine.Framework.Services.TaskState.Running)
                    {
                        task.Run();
                    }
                }
            }
        }

        /// <summary>
        /// Gets or sets the child tasks.
        /// </summary>
        /// <value>
        /// The child tasks.
        /// </value>
        /// <exception cref="System.NotImplementedException"></exception>
        public override IEnumerable<ITask> ChildTasks
        {
            get { return this.childTasks; }
        }
    }

}
